/*******************************************************\
|* Author: Trevor Sundberg
\*******************************************************/

// Header protection
#pragma once
#ifndef SKUGO_DEBUG_DRAW_HPP
#define SKUGO_DEBUG_DRAW_HPP

// Includes
#include "SkugoTypes.hpp"
#include "SkugoMath.hpp"

namespace Skugo
{
  // Cull modes used for determining how to draw a shape
  namespace CullMode
  {
    enum Enum
    {
      ShowFront,
      ShowBack,
      ShowAll
    };
  }

  // Triangle modes tell us how vertex data is layed out to make a triangle mesh
  namespace TriangleMode
  {
    enum Enum
    {
      Strip,
      Fan,
      List
    };
  }

  // Text modes tell us if there are any special effects we should apply to the text
  namespace TextMode
  {
    enum Enum
    {
      Normal,
      Shadowed,
      Bordered
    };
  }

  // The basic debug draw entity that we chain
  // in order to setup debug draw as we see fit
  class DebugDrawEntity
  {
  public:
    // Outputs: Scale
    DebugDrawEntity& Scale(float uniformScale);

    // Outputs: Scale
    DebugDrawEntity& Scale(Vec3Param axesScale);

    // Outputs: Position
    DebugDrawEntity& Position(Vec3Param position);

    // Outputs: Rotation
    DebugDrawEntity& Rotation(QuatParam rotation);

    // Outputs: Rotation
    DebugDrawEntity& Rotation(Mat3Param rotation);

    // Outputs: PreTransform
    DebugDrawEntity& PreTransform(Mat4Param transform);

    // Outputs: PostTransform
    DebugDrawEntity& PostTransform(Mat4Param transform);

    // Outputs: Color
    DebugDrawEntity& Color(Vec3Param colorFullAlpha);

    // Outputs: Color
    DebugDrawEntity& Color(Vec4Param color);

    // Outputs: Color
    DebugDrawEntity& Color(unsigned color);

    // Outputs: Priority
    DebugDrawEntity& Priority(float priority);

    // Outputs: Priority
    DebugDrawEntity& OnTop();

    // Outputs: Duration
    DebugDrawEntity& Duration(float duration);

    // Outputs: ViewScaled
    DebugDrawEntity& ViewScaled(bool value);

    // Outputs: CullMode
    DebugDrawEntity& CullMode(CullMode::Enum mode);

    // Outputs: Wireframe
    DebugDrawEntity& Wireframe(bool value);

  protected:

    // Write data to the buffer
    void Write(char* data, sizeType size);

  protected:

    // Store the written data
    // We store it as a void* as to hide the implementation details
    // so we can avoid huge amounts of inclusion in this header
    void* mData;
  };

  namespace Debug
  {
    // A 3D box shape
    struct Box : public DebugDrawEntity
    {
      // Outputs: Shape
      Box();

      // Outputs: Shape, Scale
      Box(Vec3Param extents);

      // Outputs: Shape, Scale
      static Box Extents(Vec3Param extents);
      
      // Outputs: Shape, Scale
      static Box HalfExtents(Vec3Param halfExtents);

      // Outputs: Shape, Scale, Position
      static Box MinMax(Vec3Param min, Vec2Param max);
    };

    // Other names the above shape could go by
    typedef Box Aabb, Obb, Cube;

    // A 3D sphere shape
    struct Sphere : public DebugDrawEntity
    {
      // Outputs: Shape
      Sphere();

      // Outputs: Shape, Scale
      Sphere(float radius);
    };

    // A 3D cylinder shape
    struct Cylinder : public DebugDrawEntity
    {
      // Outputs: Shape
      Cylinder();

      // Outputs: Shape, Scale
      Cylinder(float radius, float height);
    };

    // A 3D cone shape
    struct Cone : public DebugDrawEntity
    {
      // Outputs: Shape
      Cone();

      // Outputs: Shape, Scale
      Cone(float baseRadius, float height);
    };

    // A 3D triangle shape
    struct Triangle : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      Triangle(Vec3Param p1, Vec3Param p2, Vec3Param p3);
    };

    // A 3D line segment
    struct Segment : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      Segment(Vec3Param p1, Vec3Param p2);
    };

    // A 3D line that extends infinitely in both directions
    struct Line : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      Line(Vec3Param start, Vec3Param direction);
    };

    // A 3D line vector with an arrowhead at the end
    struct Vector : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      Vector(Vec3Param start, Vec3Param direction, float length = 1.0f);
    };

    // A 3D triangle mesh with vertex data only
    struct TriangleMesh : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      TriangleMesh
      (
        TriangleMode::Enum  mode,
        void*               vertexData,
        sizeType            numVertices,
        sizeType            vertexSize,
        sizeType            positionOffsetIntoVertex
      );
    };

    // A 3D triangle mesh with vertex data only
    struct TriangleMeshIndexed : public DebugDrawEntity
    {
      // Outputs: Shape, Position
      TriangleMeshIndexed
      (
        void*     indexData,
        sizeType  numIndices,
        sizeType  indexSizeBytes,
        void*     vertexData,
        sizeType  numVertices,
        sizeType  vertexSizeBytes,
        sizeType  positionOffsetIntoVertex
      );
    };

    // Text that's billboarded towards the camera
    struct Text : public DebugDrawEntity
    {
      // Outputs: Shape, Text, Scale
      Text(const char* text, float size, TextMode::Enum = TextMode::Normal);

      // Outputs: Shape, Text, Scale
      Text(String text, float size, TextMode::Enum = TextMode::Normal);
    };
  }
}

// End header protection
#endif
